
package com.rt.schedulenew.task;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.rt.schedulebase.dto.*;
import com.rt.schedulebase.entity.ExamSchedule;
import com.rt.schedulebase.entity.ExamScheduleItem;
import com.rt.schedulebase.mapper.ExamScheduleMapper;
import com.rt.schedulenew.api.*;
import com.rt.schedulenew.service.impl.*;
import com.rt.schedulenew.utils.base.CommonUtil;
import com.rt.schedulenew.utils.base.ConstantsUtil;
import com.rt.schedulenew.utils.global.JsonResult;
import com.rt.schedulenew.utils.pkgenerator.PKGeneratorSingle;
import com.rt.schedulenew.utils.util.DateUtil;
import com.rt.schedulenew.utils.util.JsonUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author ryan.li
 * @description 动态任务执行
 * @date `2022/10/31` 17:14
 */
@Component
public class DynamicScheduleTask {
    private Logger logger = LoggerFactory.getLogger(DynamicScheduleTask.class);
    @Autowired
    private ICommonService commonServiceImpl;
    @Autowired
    private IExamScheduleService examScheduleServiceImpl;
    @Autowired
    private ExamScheduleMapper examScheduleMapper;
    @Autowired
    private IConfigService configServiceImpl;
    @Autowired
    private CacheServiceImpl cacheServiceImpl;
    @Autowired
    private IExamScheduleItemService examScheduleItemServiceImpl;
    @Autowired
    private IExamSmsNoticeService examSmsNoticeService;
    @Autowired
    private IExamApplyService examApplyService;

    @Autowired
    private IExamApplyPatientService examApplyPatientService;
    @Autowired
    private IConfigService configService;

    /**
     * 释放锁定号源
     */
    public void releaseLockRun() {
        logger.info("开始执行【释放锁定的号源】");
        ConfigDto.SysTask task = configServiceImpl.getTaskInfoByMethodName("releaseLockRun");
        String cron = task.getCron();
        String regEx = "[^1-9]";
        Pattern p = Pattern.compile(regEx);
        Matcher m = p.matcher(cron);// 提取数字-分钟
        String minute = m.replaceAll("").trim();
        List<ExamApplyDto> list = examScheduleMapper.getExamScheduleForScheduleStatus(minute);
        Iterator<ExamApplyDto> iter = list.iterator();
        while (iter.hasNext()) {
            ExamApplyDto ea = iter.next();
            ExamScheduleDto es = new ExamScheduleDto();
            es.setScheduledId(ea.getScheduledId());
            List<ExamSchedule> esList = examScheduleServiceImpl.selectList(es);
            String scheduleStatus = esList.get(0).getScheduleStatus();
            if (!"01".equals(scheduleStatus)) {
                iter.remove();
            }
        }
        cancelScheduleInfo(list, ConstantsUtil.ActType.UN_LOCK.getType(), false, "【释放锁定的号源】");
    }

    public void noCheckRun() {
        Page<ExamApplyDto> page = new Page<>();
        Integer pageNo = 1;
        Integer pageSize = 100;
        page = PageHelper.startPage(pageNo, pageSize);
        List<ExamApplyDto> examApplyDtoList = examScheduleMapper.getExamApplyForApplyStatus();
        cancelScheduleInfo(null, ConstantsUtil.ActType.DEL_APPLY.getType(), false, "【释放已出院未检查号源】");
    }

    public void noPayRun() {
        List<ConfigDto.CancelScheduleNoCharge> chargeList;
        String chargeStr = cacheServiceImpl.getConfigByName(ConstantsUtil.ConfigName.CANCEL_SCHEDULE_NO_CHARGE.getKey());
        String patientSourceComm = cacheServiceImpl.getConfigByName(ConstantsUtil.ConfigName.PATIENT_SOURCE_IN.getKey());
        if (StringUtils.isBlank(patientSourceComm)) {
            patientSourceComm = "住院";
        }
        if (StringUtils.isNotBlank(chargeStr)) {
            chargeList = JsonUtil.toList(chargeStr, ConfigDto.CancelScheduleNoCharge.class);
            if (chargeList != null && chargeList.size() > 0) {
                for (ConfigDto.CancelScheduleNoCharge charge : chargeList) {
                    ExamApplyDto ea = new ExamApplyDto();
                    ea.setExamClasses(charge.getExamClass());
                    ea.setPatientSources(charge.getPatientSource());
                    ea.setCancelMin(charge.getCancelMin());
                    if (charge.getPatientSource() == null || charge.getPatientSource().size() == 0) {
                        ea.setPatientSource(patientSourceComm);
                    }
                    List<ExamApplyDto> noChargeApplies = examScheduleMapper.getExamApplyForNoCharge(ea);
                    cancelScheduleInfo(noChargeApplies, ConstantsUtil.ActType.CANCEL.getType(), false, "【释放未缴费号源】");
                }
            }
        }
        List<ConfigDto.CancelScheduleNoCharge> chargeByTimeList;
        String chargeByTime = cacheServiceImpl.getConfigByName(ConstantsUtil.ConfigName.CANCEL_SCHEDULE_NO_CHARGE_BY_TIME.getKey());
        if (StringUtils.isNotBlank(chargeByTime)) {
            chargeByTimeList = JsonUtil.toList(chargeByTime, ConfigDto.CancelScheduleNoCharge.class);
            if (chargeByTimeList != null && chargeByTimeList.size() > 0) {
                for (ConfigDto.CancelScheduleNoCharge charge2 : chargeByTimeList) {
                    String cancelTime = charge2.getCancelTime();
                    String addMinute = DateUtil.addMinute1(3);
                    String minusMinute = DateUtil.addMinute1(-2);
                    if (cancelTime.compareTo(minusMinute) >= 0 && cancelTime.compareTo(addMinute) < 0) {
                        ExamApplyDto ea2 = new ExamApplyDto();
                        ea2.setExamClasses(charge2.getExamClass());
                        if (charge2.getPatientSource() == null || charge2.getPatientSource().size() == 0) {
                            ea2.setPatientSource(patientSourceComm);
                        }
                        ea2.setPatientSources(charge2.getPatientSource());
                        List<ExamApplyDto> list4 = examScheduleMapper.getExamApplyForNoCharge(ea2);
                        cancelScheduleInfo(list4, ConstantsUtil.ActType.CANCEL.getType(), false, "【释放未缴费号源】");
                    }
                }
            }
        }
    }

    public void noSignRun() {
        List<ExamApplyDto> list4 = examScheduleMapper.getExamApplyForNoSign();
        cancelScheduleInfo(list4, ConstantsUtil.ActType.CANCEL.getType(), true, "【释放超时未报到号源】");
    }

    public void advanceSignRun() {
        String freeSourceByEarlySign = cacheServiceImpl.getConfigByName(ConstantsUtil.ConfigName.FREE_SOURCE_BY_EARLY_SIGN.getKey());
        List<ConfigDto.FreeSourceByEarlySign> freeSourceByEarlySignList = new ArrayList<ConfigDto.FreeSourceByEarlySign>();
        if (StringUtils.isNotBlank(freeSourceByEarlySign)) {
            freeSourceByEarlySignList = JsonUtil.toList(freeSourceByEarlySign, ConfigDto.FreeSourceByEarlySign.class);
            if (freeSourceByEarlySignList != null && freeSourceByEarlySignList.size() > 0) {
                for (ConfigDto.FreeSourceByEarlySign signList : freeSourceByEarlySignList) {
                    ExamApplyDto dto = new ExamApplyDto();
                    dto.setExamClasses(signList.getExamClass());
                    String reg = "[^1-9]";
                    Pattern pp = Pattern.compile(reg);
                    Matcher mr = pp.matcher(signList.getLeadTime());
                    String leadTime = mr.replaceAll("").trim();
                    if (StringUtils.isBlank(leadTime)) {
                        continue;
                    }
                    boolean status = signList.getLeadTime().contains("天");
                    if (status) {
                        dto.setCancelDays(Integer.parseInt(leadTime));
                    } else {
                        dto.setCancelHours(Integer.parseInt(leadTime) * 60);
                    }
                    List<ExamApplyDto> list5 = examScheduleMapper.getFreeSourceByEarlySign(dto);
                    List<ExamApplyDto> list6 = new ArrayList<>();
                    list6.addAll(list5);
                    cancelScheduleInfo(list5, ConstantsUtil.ActType.CANCEL.getType(), false, "【释放提前登记或检查的号源】");
                    for (ExamApplyDto examApplyDto : list6) {
                        String scheduledId = PKGeneratorSingle.getInstance().nextPKStr();
                        ExamSchedule es = new ExamSchedule();
                        es.setScheduledId(scheduledId);
                        es.setScheduleStatus("08");
                        es.setScheduledDate(DateUtil.getCurrDateStr());
                        es.setScheduleApm("00:00~00:00");
                        es.setQueueName("无");
                        es.setMemo("释放号源后插入记录");
                        examScheduleServiceImpl.insertSelective(es);
                        ExamScheduleItem esi = new ExamScheduleItem();
                        esi.setScheduledId(scheduledId);
                        esi.setExamStatus("10");
                        esi.setApplyNo(examApplyDto.getApplyNo());
                        esi.setItemNo(examApplyDto.getItemNo());
                        examScheduleItemServiceImpl.insertSelective(esi);
                    }
                }
            }
        }
    }

    /**
     * 取消预约
     *
     * @param list
     * @param type
     * @param recedeCostFlag
     * @param desc
     */
    private void cancelScheduleInfo(List<ExamApplyDto> list, String type, boolean recedeCostFlag, String desc) {
        if (CollectionUtils.isEmpty(list)) return;

        Map<String, Object> mergerNoMap = new HashMap<>();
        List<String> idList = new ArrayList<>();
        Iterator<ExamApplyDto> it = list.iterator();
        StringBuffer mergerNo = new StringBuffer();
        while (it.hasNext()) {
            ExamApplyDto e = it.next();
            if (ConstantsUtil.ActType.DEL_APPLY.getType().equals(type) && StringUtils.isBlank(e.getApplyStatus())) {
                it.remove();
            } else {
                if (idList.contains(e.getScheduledId())) {
                    mergerNo.append("," + e.getApplyNo() + "-" + e.getItemNo());
                    it.remove();
                } else {
                    mergerNo = new StringBuffer();
                    mergerNo.append("," + e.getApplyNo() + "-" + e.getItemNo());
                    idList.add(e.getScheduledId());
                }
                mergerNoMap.put(e.getScheduledId(), StringUtils.isNotBlank(mergerNo) ? mergerNo.substring(1) : (e.getApplyNo() + "-" + e.getItemNo()));
            }
        }
        for (ExamApplyDto ea : list) {
            ExamApplyDto dto = new ExamApplyDto();
            String mergeNo = mergerNoMap.get(ea.getScheduledId()).toString();
            dto.setOrgans(ea.getOrgans());
            dto.setApplyNo(ea.getApplyNo());
            dto.setScheduledId(ea.getScheduledId());
            dto.setNextApmRatio(ea.getNextApmRatio());
            dto.setScheduleDate(ea.getScheduledDate());
            dto.setMergeNo(mergeNo);
            dto.setRegularIdList(Arrays.asList(ea.getRegularId()));
            dto.setApmCode(ea.getApmCode());
            dto.setExamClass(ea.getExamClass());
            dto.setTerminalType(ConstantsUtil.TerminalType.SYSTEM.getType());
            boolean isExamClass4Organ = ea.getOrgans() != null;
            DictUsersDto dictUsers = new DictUsersDto();
            dictUsers.setUserId("system");
            dictUsers.setName("后台服务");
            dictUsers.setIpAddress("system");
            if (recedeCostFlag) {
                JsonResult recedeCostResult = commonServiceImpl.recedeCost(dto, ConstantsUtil.ActType.CANCEL.getType(), dictUsers);
                if (recedeCostResult != null && !"0".equals(recedeCostResult.getStatus())) {
                    continue;
                }
            }
            ea.setMergeNo(mergerNoMap.get(ea.getScheduledId()).toString());
            Double reqCount = 1.0;
            if (isExamClass4Organ) {
                List<ExamApplyItemDto> items = commonServiceImpl.getExamApplyItem(mergerNoMap.get(ea.getScheduledId()).toString(), ea);
                reqCount = commonServiceImpl.getOrgansReqCount(ea);
                if (reqCount == null) {
                    reqCount = commonServiceImpl.getReqOrganByItems(items);
                }
            }
            dto.setReqCount(reqCount);
            ExamScheduleItem its = new ExamScheduleItem();
            its.setScheduledId(ea.getScheduledId());
            List<ExamScheduleItem> items2 = examScheduleItemServiceImpl.getItemList(its);
            if (ConstantsUtil.ActType.CANCEL.getType().equals(type) && !"01".equals(ea.getScheduleStatus())) {
                ExamApplyDto examApplyDto = new ExamApplyDto();
                List<String> applyNos = CommonUtil.mergeNo2ApplyNos(mergeNo);
                examApplyDto.setApplyNos(applyNos);
                examApplyDto.setActType(type);
                examApplyDto.setExamClass(ea.getExamClass());
                examApplyDto.setScheduledId(ea.getScheduledId());
                examApplyDto.setMergeNo(mergeNo);
                examApplyDto.setApplyNo(ea.getApplyNo());
                examApplyDto.setTerminalType(ConstantsUtil.TerminalType.SYSTEM.getType());
                examApplyDto.setScheduleDate(ea.getScheduleDate());
                examApplyDto.setName("system");
                examApplyDto.setUserId("system");
                examApplyDto.setStaffNo("system");
                examApplyDto.setScheduleApm(ea.getScheduleApm());
                examApplyDto.setScheduleHospitalName(ea.getScheduleHospitalName());
                examApplyDto.setPerformDeptName(ea.getPerformDeptName());
                String itemNameStr = "";
                for (ExamScheduleItem item : items2) {
                    itemNameStr = itemNameStr + item.getItemName() + ";";
                }
                examApplyDto.setItemNameStr(itemNameStr);
                ExamApplyDto ea2 = new ExamApplyDto();
                ea2.setMergeNo(mergeNo);
                if (applyNos != null && applyNos.size() > 0) {
                    ExamSmsNoticeDto esn = new ExamSmsNoticeDto();
                    esn.setApplyNos(applyNos);
                    examSmsNoticeService.delete(esn);
                }
                commonServiceImpl.addExamSmsNotice(ea, ConstantsUtil.SmsType.CANCLE_SCHEDULE.getType(), ea2);
                configServiceImpl.isScheduleSync(examApplyDto, type, ConstantsUtil.ScheduleStatus.NINE.getStatus());
            }
            commonServiceImpl.cancelScheduleInfo(dto, isExamClass4Organ);
            if (ConstantsUtil.ActType.DEL_APPLY.getType().equals(type) && StringUtils.isBlank(ea.getApplyStatus())) {
                continue;
            }
            ea.setActType(type);
            ea.setScheduleDate(ea.getScheduledDate());
            ea.setTerminalType(ConstantsUtil.TerminalType.SYSTEM.getType());
            ea.setDesc(desc);
            StringBuffer sb = new StringBuffer();
            if (items2 == null || items2.size() <= 0) {
                continue;
            }
            for (ExamScheduleItem esi : items2) {
                sb.append("," + esi.getApplyNo() + "-" + esi.getItemNo());
            }
            List<ExamApplyItemDto> item2 = commonServiceImpl.getExamApplyItem(sb.substring(1), ea);
            ea.setItems(item2);
            ea.setProcess(dto.getProcess());
            ea.setNextOrganProcess(dto.getNextOrganProcess());
            commonServiceImpl.addExamScheduleAct(ea, dictUsers);
        }
    }

    /***
     * 自动预约任务
     */
    public void autoScheduleTask() {
        logger.info("自动预约任务开始执行....");
        String autoTaskStr = cacheServiceImpl.getConfigByName(ConstantsUtil.ConfigName.AUTO_SCHEDULE_BY_TIMING_TASK.getKey());
        if (StringUtils.isBlank(autoTaskStr)) {
            return;
        }
        logger.info("自动预约任务开始执行2....{}", autoTaskStr);
        List<ConfigDto.CommonSet> list = JsonUtil.toList(autoTaskStr, ConfigDto.CommonSet.class);
        for (ConfigDto.CommonSet commonSet : list) {
            String time = DateUtil.getCurrentDate() + " " + commonSet.getLimitTime() + ":00";
            String currentDateTime = DateUtil.getCurrentDateTime();
            int diff = DateUtil.diffMin(DateUtil.parse(time, DateUtil.FORMAT_DATETIME), DateUtil.parse(currentDateTime, DateUtil.FORMAT_DATETIME));
            if (diff == 0 || diff == 1) {
                ExamApplyDto patientDto = new ExamApplyDto();
                patientDto.setReqDateStart(DateUtil.addDays(-((commonSet.getDay() != null) ? commonSet.getDay() : 0)));
                patientDto.setReqDateEnd(DateUtil.getCurrDateStr());
                patientDto.setExamClass(StringUtils.join(commonSet.getExamClass(), ","));
                patientDto.setPatientSource(StringUtils.join(commonSet.getPatientSource(), ","));
                patientDto.setItemStatus("0");
                patientDto.setScheduleStatus(ConstantsUtil.ScheduleStatus.ZERO.getStatus());
                patientDto.setTerminalType(ConstantsUtil.TerminalType.SYSTEM.getType());
                JsonResult patientJsonResult = examApplyPatientService.getPatientList(patientDto, false);
                if (patientJsonResult == null && !"0".equals(patientJsonResult.getStatus())) {
                    logger.error("获取符合自动预约条件的患者列表异常:" + JsonUtil.toJson(patientDto) + "，返回结果:" + JsonUtil.toJson(patientJsonResult));
                    continue;
                }
                List<ExamApplyDto> examApplyPatientList = (List<ExamApplyDto>) patientJsonResult.getResult();
                for (ExamApplyDto examApplyPatient : examApplyPatientList) {
                    ExamApplyDto examApply = new ExamApplyDto();
                    examApply.setSickId(examApplyPatient.getSickId());
                    examApply.setExamClass(StringUtils.join(commonSet.getExamClass(), ","));
                    examApply.setHistoryFlag("1");
                    examApply.setPlanMode("1");
                    examApply.setTerminalType("G");
                    examApply.setUserId("system");
                    JsonResult jsonResult = examApplyPatientService.getPatientApplyList(examApply);
                    if (jsonResult == null || !"0".equals(jsonResult.getStatus())) {
                        logger.error("获取到申请单列表异常:" + JsonUtil.toJson(examApply) + "，返回结果:" + JsonUtil.toJson(jsonResult));
                        continue;
                    }
                    List<ExamApplyDto> applyDtoList = (List<ExamApplyDto>) jsonResult.getResult();
                    if (CollectionUtils.isEmpty(applyDtoList)) {
                        logger.error("没有获取到申请单列表:" + JsonUtil.toJson(examApply) + "，返回结果:" + JsonUtil.toJson(jsonResult));
                        continue;
                    }
                    for (ExamApplyDto ea : applyDtoList) {
                        if ("1".equals(ea.getScheduleStatus())) {
                            ExamApplyDto dto = new ExamApplyDto();
                            dto.setApplyNo(ea.getApplyNo());
                            dto.setMergeNo(ea.getMergeNo());
                            dto.setHospitalCode(ea.getHospitalCode());
                            dto.setTerminalType("G");
                            dto.setUserId("system");
                            JsonResult confirmResult = null;
                            try {
                                confirmResult = examApplyService.confirmApm(dto);
                            } catch (Exception e) {
                                throw new RuntimeException(e);
                            }
                            if (!"0".equals(confirmResult.getStatus())) {
                                logger.error(ea.getApplyNo() + " 定时自动预约信息确认预约时段失败！");
                                continue;
                            }
                            ExamApplyDto examApplyDto = new ExamApplyDto();
                            List<String> appNos = CommonUtil.mergeNo2ApplyNos(dto.getMergeNo());
                            examApplyDto.setApplyNos(appNos);
                            ExamApplyDto applyResult = (ExamApplyDto) confirmResult.getResult();
                            String actType = applyResult.getActType();
                            examApplyDto.setActType(actType);
                            examApplyDto.setExamClass(applyResult.getExamClass());
                            examApplyDto.setScheduledId(applyResult.getScheduledId());
                            examApplyDto.setMergeNo(applyResult.getMergeNo());
                            examApplyDto.setApplyNo(dto.getApplyNo());
                            examApplyDto.setUserId("system");
                            boolean isSucc = configService.isScheduleSync(examApplyDto, actType, ConstantsUtil.ScheduleStatus.EIGHT.getStatus());
                            if (!isSucc) {
                                logger.error(ea.getApplyNo() + " 定时自动预约信息推送失败");
                            }
                        } else {
                            logger.error(ea.getApplyNo() + " 申请单状态不对! ScheduleStatus:" + ea.getScheduleStatus());
                        }
                    }
                }
            }
        }
    }

}
